#include "sync.h"
#include "print.h"
#include "global.h"
#include "interrupt.h"
#include "debug.h"

void init_lock(lock* plock){
	init_semphore(&plock->sem,1);
	plock->repeate_nr=0;
	plock->holder=NULL;
}

void init_semphore(semphore* psem,int32_t value){
	list_init(&psem->waiters);
	psem->value=value;
}

void sem_down(semphore* psem){
	task_tcb* curr;	
	intr_status old_status=intr_disable();
	curr=current_thread();
	while(!psem->value){
		ASSERT(!elem_find(&psem->waiters,&curr->gen_tag));
		list_append(&psem->waiters,&curr->gen_tag);
		thread_block(TASK_BLOCKED);
	}
	psem->value--;
	ASSERT(psem->value==0);
	intr_set_status(old_status);
}

void sem_up(semphore* psem){
	intr_status old_status=intr_disable();
	if(list_len(&psem->waiters)){
		thread_unblock(elem2entry(task_tcb,gen_tag,list_pop(&psem->waiters)));
	}
	psem->value++;
	ASSERT(psem->value==1);
	intr_set_status(old_status);
}

void lock_acquire(lock* plock){
	task_tcb* curr;	
	curr=current_thread();
	if(plock->holder!=curr){
		sem_down(&plock->sem);
		plock->holder=curr;
	}else{
		plock->repeate_nr++;
	}
}

void lock_release(lock* plock){
	task_tcb* curr;	
	curr=current_thread();
	ASSERT(curr==plock->holder);
	if(plock->repeate_nr>0){
		plock->repeate_nr--;
		return;
	}
	plock->holder=NULL;
	sem_up(&plock->sem);
}
